#include "gd32f30x.h"
#include "stdint.h"
#include "stdio.h"
#include "DevicesDelay.h"
#include "DevicesSPI.h"


void vSPI0DMAInit(void)
{
    dma_parameter_struct dma_init_struct = {0};

    /* enable DMA0 */
    rcu_periph_clock_enable(RCU_DMA0);

    /* deinitialize DMA channel2(spi0 tx) */
    dma_deinit(DMA0, DMA_CH2);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = 0;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 0;
    dma_init_struct.periph_addr = ((uint32_t)&SPI_DATA(SPI0));
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_init(DMA0, DMA_CH2, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH2);
    dma_memory_to_memory_disable(DMA0, DMA_CH2);
    /* disable DMA channel */
    dma_channel_disable(DMA0, DMA_CH2);

    /* DMA enable for transmission */
    spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);


    /* DMAx interrupt configuration */
    nvic_irq_enable(DMA0_Channel2_IRQn, 3, 0);
    /* enable DMAx interrupt */
    dma_interrupt_enable(DMA0, DMA_CH2, DMA_INT_FTF);
}

void vSPI0Init(void)
{
    spi_parameter_struct spi_init_struct = {0};

    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_SPI0);

    SPI0_NSS_SET_HIGH();

    /* SPI0 GPIO config:SCK, MOSI */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
    /* SPI0 GPIO config:MISO */
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    /* SPI0 GPIO config:NSS */
    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

    vSPI0DMAInit();

    /* SPI0 parameter config */
    spi_i2s_deinit(SPI0);
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_4;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi_init_struct);

    /* SPI enable */
    spi_enable(SPI0);
}

void vSPI1DMAInit(void)
{
    dma_parameter_struct dma_init_struct = {0};

    /* enable DMA0 */
    rcu_periph_clock_enable(RCU_DMA0);

    /* deinitialize DMA channel3(spi1 rx) */
    dma_deinit(DMA0, DMA_CH3);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = 0;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 0;
    dma_init_struct.periph_addr = ((uint32_t)&SPI_DATA(SPI0));
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_LOW;
    dma_init(DMA0, DMA_CH3, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH3);
    dma_memory_to_memory_disable(DMA0, DMA_CH3);
    /* disable DMA channel */
    dma_channel_disable(DMA0, DMA_CH3);

    /* DMA enable for transmission */
    spi_dma_enable(SPI1, SPI_DMA_RECEIVE);


    /* DMAx interrupt configuration */
    nvic_irq_enable(DMA0_Channel3_IRQn, 3, 0);
    /* enable DMAx interrupt */
    dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);
}

void vSPI1Init(void)
{
    spi_parameter_struct spi_init_struct = {0};

    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_SPI1);

    SPI1_NSS_SET_HIGH();

    /* SPI0 GPIO config:SCK, MOSI */
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_15);
    /* SPI0 GPIO config:MISO */
    gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    /* SPI0 GPIO config:NSS */
    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);

//    vSPI1DMAInit();

    /* SPI0 parameter config */
    spi_i2s_deinit(SPI1);
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_2;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI1, &spi_init_struct);

    /* SPI enable */
    spi_enable(SPI1);
}

uint8_t ucSPIWriteReadByte(uint32_t uiSpiPeriph, uint8_t ucByte)
{
    int32_t iTime;

    for(iTime = 0; (RESET == (SPI_STAT(uiSpiPeriph) & SPI_FLAG_TBE)) && (iTime < 10000); ++iTime);
    SPI_DATA(uiSpiPeriph) = ucByte;

    /* 等待发送完成 */
    for(iTime = 0; (RESET != (SPI_STAT(uiSpiPeriph) & SPI_FLAG_TRANS)) && (iTime < 20000); ++iTime);

    for(iTime = 0; (RESET == (SPI_STAT(uiSpiPeriph) & SPI_FLAG_RBNE)) && (iTime < 10000); ++iTime);
    ucByte = SPI_DATA(uiSpiPeriph);

    return ucByte;
}

int8_t cSPIWriteDatas(uint32_t uiSpiPeriph, void *pvBuff, int32_t iLength)
{
    uint8_t *pucBuffer = pvBuff;
    int32_t iTime;

    if((pvBuff == NULL) || (iLength < 1))
        return -1;

    while((iLength--) > 0)
    {
        for(iTime = 0; (RESET == (SPI_STAT(uiSpiPeriph) & SPI_FLAG_TBE)) && (iTime < 10000); ++iTime);
        SPI_DATA(uiSpiPeriph) = *pucBuffer++;
    }

    /* 等待最后2个字节发送完成 */
    for(iTime = 0; (RESET != (SPI_STAT(uiSpiPeriph) & SPI_FLAG_TRANS)) && (iTime < 20000); ++iTime);

    for(iTime = 0; (RESET == (SPI_STAT(uiSpiPeriph) & SPI_FLAG_RBNE)) && (iTime < 10000); ++iTime);
    (void)SPI_DATA(uiSpiPeriph);

    return 0;
}

int8_t cSPIReadDatas(uint32_t uiSpiPeriph, void *pvBuff, int32_t iLength)
{
    uint8_t *pucBuffer = pvBuff;
    int32_t iTime;

    if((pvBuff == NULL) || (iLength < 1))
        return -1;

    while((iLength--) > 0)
    {
        SPI_DATA(uiSpiPeriph) = 0xFFFF;

        for(iTime = 0; (RESET == (SPI_STAT(uiSpiPeriph) & SPI_FLAG_RBNE)) && (iTime < 10000); ++iTime);
        *pucBuffer++ = SPI_DATA(uiSpiPeriph);
    }

    return 0;
}


/**
 * @brief  设置DMA的数据传输长度，并启动DMA传输
 * @param  DMAy_Channelx：   相应DMA的通道
           Length：          传输长度
 * @retval 无
 */
void vSPIxDmaAddrAndLenthSet(uint32_t dma_periph, dma_channel_enum channelx, uint32_t uiSourceAddress, uint32_t uiTargetAddress, uint32_t uiLength)
{
    uint32_t uiTime;

    /* Disable the peripheral */
    dma_channel_disable(dma_periph, channelx);
    for(uiTime = 0; (((DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_CHEN) != 0) && (uiTime < 10000)); ++uiTime);

    /* 必须要清除所有中断状态，才允许使能DMA */
    dma_flag_clear(dma_periph, channelx, DMA_FLAG_G | DMA_FLAG_FTF | DMA_FLAG_HTF | DMA_FLAG_ERR);

    /* configure memory base address */
    dma_memory_address_config(dma_periph, channelx, uiSourceAddress);

    /* configure peripheral base address */
    dma_periph_address_config(dma_periph, channelx, uiTargetAddress);

    /* Configure DMA Stream data length */
    dma_transfer_number_config(dma_periph, channelx, uiLength);

//    /* configure the direction of data transfer on the channel   */
//    dma_transfer_direction_config(dma_periph, channelx, cDirection);

    /* Enable the Peripheral */
    dma_channel_enable(dma_periph, channelx);
    for(uiTime = 0; (((DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_CHEN) == 0) && (uiTime < 10000)); ++uiTime);
}

int8_t cSPIDmaWriteDatas(uint32_t uiSpiPeriph, void *pvDatas, int32_t iLength, int32_t iWaitUs)
{
    dma_channel_enum enumChannelx;
    uint32_t dma_periph;
    int32_t iTime;

    if(iLength < 1)
        return 1;

    switch(uiSpiPeriph)
    {
        case SPI0: dma_periph = DMA0; enumChannelx = DMA_CH2; break;
        case SPI1: dma_periph = DMA0; enumChannelx = DMA_CH4; break;
        case SPI2: dma_periph = DMA1; enumChannelx = DMA_CH1; break;

        default : printf("cSPIDmaWriteDatas channel error.\r\n"); return 2;
    }

    /* 等待上次DMA传输完成 */
    while((dma_flag_get(dma_periph, enumChannelx, DMA_FLAG_FTF) == RESET) &&
         ((DMA_CHCTL(dma_periph, enumChannelx) & DMA_CHXCTL_CHEN) != 0)   &&
          (DMA_CHCNT(dma_periph, enumChannelx) != 0));

    /* 设置传输地址与长度，并启动DMA发送 */
    vSPIxDmaAddrAndLenthSet(dma_periph, enumChannelx, (uint32_t)pvDatas, (uint32_t)(&SPI_DATA(uiSpiPeriph)), iLength);

    spi_dma_enable(uiSpiPeriph, SPI_DMA_TRANSMIT);

    /* 等待本次DMA传输完成 */
    if(iWaitUs > 0)
    {
        while(((iWaitUs--) > 0)                                               &&
             ((DMA_CHCTL(dma_periph, enumChannelx) & DMA_CHXCTL_CHEN) != 0)   &&
              (dma_flag_get(dma_periph, enumChannelx, DMA_FLAG_FTF) == RESET) &&
              (DMA_CHCNT(dma_periph, enumChannelx) != 0))
        {
            vDelayUs(1);
        }

        /* 等待最后2个字节发送完成 */
        for(iTime = 0; (RESET != (SPI_STAT(uiSpiPeriph) & SPI_FLAG_TRANS)) && (iTime < 20000); ++iTime);
    }

    return 0;
}

int8_t cSPITransStatus(uint32_t uiSpiPeriph)
{
    return (RESET != (SPI_STAT(uiSpiPeriph) & SPI_FLAG_TRANS));
}
